/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.lcm.metadata.core;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.inspur.edp.lcm.metadata.api.ConfigData.gspproject.ProjectConfiguration;
import com.inspur.edp.lcm.metadata.api.entity.*;
import com.inspur.edp.lcm.metadata.api.entity.vendor.VendorConfig;
import com.inspur.edp.lcm.metadata.api.exception.ErrorCodes;
import com.inspur.edp.lcm.metadata.api.exception.LcmFileDevException;
import com.inspur.edp.lcm.metadata.api.exception.LcmMetadataDevException;
import com.inspur.edp.lcm.metadata.api.exception.LcmParseDevException;
import com.inspur.edp.lcm.metadata.common.FileServiceImp;
import com.inspur.edp.lcm.metadata.common.SerializerUtils;
import com.inspur.edp.lcm.metadata.common.Utils;
import com.inspur.edp.lcm.metadata.common.configuration.GspProjectConfigurationHelper;
import com.inspur.edp.lcm.metadata.common.configuration.MetadataTypeHelper;
import com.inspur.edp.lcm.metadata.common.configuration.VendorConfigLoader;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhaoleitr
 */
public class GspProjectCoreService {
    private final FileServiceImp fileService = new FileServiceImp();

    public GspProject getGspProjectInfo(String absolutePath) {
        Utils.checkEmpty(absolutePath, "工程路径不能为空。");
        String projPath = MetadataProjectCoreService.getCurrent().getProjPath(absolutePath);
        String fullName = fileService.getCombinePath(projPath, Utils.getGspProjectName());
        if (!fileService.isFileExist(fullName)) {
            throw new LcmFileDevException(ErrorCodes.ECP_FILE_DEV_0001, fullName);
        }
        String projStr = fileService.fileRead(Utils.handlePath(fullName));

        ObjectMapper objectMapper = Utils.getMapper();
        GspProject project;
        try {
            project = objectMapper.readValue(projStr, GspProject.class);
        } catch (IOException e) {
            throw new LcmParseDevException(e, ErrorCodes.ECP_PARSE_DEV_0001, fullName);
        }
        return project;
    }

    public List<ProjectConfiguration> getGspProjectTypeInfo() {
        return GspProjectConfigurationHelper.getInstance().getGspProjectConfigurations();
    }

    public Map<String, MetadataTypeWithProjectDto> getMetadataTypeWithProjectDtoMap(String boPath) {
        Utils.checkEmpty(boPath, "bo路径不可为空");
        List<GspProjectDto> projectsInBo = getProjectsInBo(boPath);
        List<MetadataType> metadataTypeList = MetadataTypeHelper.getInstance().getMetadataTypes();
        Map<String, MetadataTypeWithProjectDto> metadataTypeWithProjectDtoMap = new HashMap<>();
        for (MetadataType metadataType : metadataTypeList) {
            if (!metadataType.isFlag()) {
                continue;
            }
            List<GspProjectDto> gspProjectDtoList;
            if (ProjectTypeApply.all.equals(metadataType.getApply())) {
                gspProjectDtoList = projectsInBo;
            } else {
                gspProjectDtoList = projectsInBo.stream()
                        .filter(gspProjectDto
                                -> metadataType.getApply() != null
                                && metadataType.getApply().toString().equals(gspProjectDto.getGspProject().getProjectType().toString()))
                        .collect(Collectors.toList());
            }
            metadataTypeWithProjectDtoMap.put(metadataType.getTypeCode(), new MetadataTypeWithProjectDto(metadataType, gspProjectDtoList));
        }
        return metadataTypeWithProjectDtoMap;
    }

    private List<GspProjectDto> getProjectsInBo(String boPath) {
        Utils.checkEmpty(boPath, "bo路径不可为空");
        List<GspProjectDto> gspProjectDtoList = new ArrayList<>();
        boolean isBackendExist = false;
        boolean isFrontendExist = false;
        // 新建的bo，bo路径不存在，在创建工程的时候会自动创建，所以可直接返回fakeProject
        File boFile = new File(boPath);
        if (boFile.exists()) {
            File[] dirs = boFile.listFiles(File::isDirectory);
            if (dirs != null) {
                for (File dir : dirs) {
                    File[] files = dir.listFiles();
                    if (files == null) {
                        continue;
                    }
                    for (File file : files) {
                        if (file.getName().equals(Utils.getGspProjectName())) {
                            String projStr = fileService.fileRead(file.getPath());
                            GspProject gspProject = SerializerUtils.deserialize(projStr, GspProject.class);
                            switch (gspProject.getProjectType()) {
                                case backend:
                                    isBackendExist = true;
                                    break;
                                case frontend:
                                    isFrontendExist = true;
                                    break;
                            }
                            gspProjectDtoList.add(new GspProjectDto(gspProject, true));
                            break;
                        }
                    }
                }
            }
        }
        if (!isBackendExist) {
            gspProjectDtoList.add(getFakeProject(boPath, ProjectType.backend));
        }
        if (!isFrontendExist) {
            gspProjectDtoList.add(getFakeProject(boPath, ProjectType.frontend));
        }
        return gspProjectDtoList;
    }

    private GspProjectDto getFakeProject(String boPath, ProjectType projectType) {
        Utils.checkEmpty(boPath, "bo路径不可为空");
        // split的参数是正则表达式，如果要按照\进行分离，得写\\\\，无法适用于全系统
        String[] names = Paths.get(boPath).normalize().toString().replace(File.separator, "/").split("/");
        if (names.length < 3) {
            throw new LcmMetadataDevException(ErrorCodes.ECP_METADATA_DEV_0006, boPath);
        }
        String appCode = names[names.length - 3];
        String suCode = names[names.length - 2];
        String boCode = names[names.length - 1];
        VendorConfig vendorConfig = VendorConfigLoader.getInstance().getVendorConfig();
        String projectNameSpace = vendorConfig.getVendorCode().getValue() + Utils.DOT + vendorConfig.getProductCode().getValue() + Utils.DOT + appCode + Utils.DOT + suCode + Utils.DOT + boCode + Utils.DOT + boCode + Utils.DOT + projectType.getSuffix();
        String metadataProjectName = Utils.BO + Utils.HYPHON + boCode +  Utils.HYPHON + projectType.getSuffix();
        String metadataPackageName = projectNameSpace;
        GspProject gspProject = new GspProject(appCode, suCode, boCode, projectNameSpace, metadataProjectName, metadataPackageName, projectType);
        return new GspProjectDto(gspProject, false);
    }
}
